package com.sfang.common.base.response;

import cn.hutool.http.HttpStatus;
import com.sfang.common.base.enums.BaseEnums;
import com.sfang.common.base.enums.SystemEnum;
import com.sfang.common.base.exception.BusinessException;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import org.slf4j.MDC;
import org.springframework.util.ObjectUtils;

import java.io.Serializable;
import java.util.Objects;

/**
 * 公共响应
 *
 */
@Data
@AllArgsConstructor
public class Response<T> implements Serializable {

    private static final long serialVersionUID = 1L;

    private static final String TRACE_ID = "traceId";

    @ApiModelProperty(notes = "数据")
    private T data;

    @ApiModelProperty(notes = "状态码 200:成功")
    private Integer code;

    @ApiModelProperty(notes = "请求返回信息")
    private String msg;

    @ApiModelProperty(notes = "返回trackId")
    private String traceId;

    /**
     * 响应成功
     *
     * @param data 响应数据
     * @param <T>  泛型参数
     * @return {@link Response}
     */
    public static <T> Response<T> ok(T data) {
        return ok(data, "响应成功");
    }

    /**
     * 响应成功
     *
     * @param <T> 泛型参数
     * @return {@link Response}
     */
    public static <T> Response<T> ok() {
        return ok(null, "响应成功");
    }

    /**
     * 响应成功
     *
     * @param data 响应数据
     * @param msg  响应消息
     * @param <T>  泛型参数
     * @return {@link Response}
     */
    public static <T> Response<T> ok(T data, String msg) {
        return new Response<>(data, HttpStatus.HTTP_OK, msg, MDC.get(TRACE_ID));
    }

    /**
     * 响应失败
     *
     * @param <T> 泛型参数
     * @return {@link Response}
     */
    public static <T> Response<T> error() {
        return error(HttpStatus.HTTP_INTERNAL_ERROR, "响应失败");
    }

    /**
     * 响应失败
     *
     * @param msg 失败消息
     * @param <T> 泛型参数
     * @return {@link Response}
     */
    public static <T> Response<T> error(String msg) {
        return error(HttpStatus.HTTP_INTERNAL_ERROR, msg);
    }

    /**
     * 响应失败
     *
     * @param resultEnums 响应枚举
     * @param <T>         泛型参数
     * @return {@link Response}
     */
    public static <T> Response<T> error(BaseEnums resultEnums) {
        return new Response<>(null, resultEnums.getCode(), resultEnums.getMsg(), MDC.get(TRACE_ID));
    }

    /**
     * 响应失败
     *
     * @param code 状态吗
     * @param msg  失败消息
     * @param <T>  泛型参数
     * @return {@link Response}
     */
    public static <T> Response<T> error(Integer code, String msg) {
        return new Response<>(null, code, msg, MDC.get(TRACE_ID));
    }

    /**
     * 响应失败
     *
     * @param data 响应数据
     * @param code 状态码
     * @param msg  失败消息
     * @param <T>  泛型参数
     * @return {@link Response}
     */
    public static <T> Response<T> error(T data,Integer code, String msg) {
        return new Response<>(data, code, msg, MDC.get(TRACE_ID));
    }

    /**
     * 包装
     *
     * @param flag 包装响应
     * @param <T>  泛型参数
     * @return {@link Response}
     */
    public static <T> Response<T> wrap(boolean flag) {
        return flag ? ok() : error();
    }

    /**
     * 包装
     *
     * @param msg  响应消息
     * @param flag 包装响应
     * @param <T>  泛型参数
     * @return {@link Response}
     */
    public static <T> Response<T> wrap(boolean flag, String msg) {
        return flag ? ok(null, msg) : error(msg);
    }

    /**
     * 检查响应
     *
     * @param response this
     * @param <T>      泛型
     */
    public static <T> void checkResponse(Response<T> response) {
        if (Objects.isNull(response)) {
            throw new BusinessException(SystemEnum.INTERNAL_SERVER_ERROR);
        }
        if (!response.isSuccess()) {
            throw new BusinessException(response.code, response.getMsg());
        }
    }

    /**
     * 获取响应200的数据
     * 注：但返回数据data可能为null或空
     *
     * @param response this
     * @param <T>      泛型
     */
    public static <T> T getSuccessData(Response<T> response) {
        if (Objects.isNull(response)) {
            throw new BusinessException(SystemEnum.INTERNAL_SERVER_ERROR);
        }
        if (!response.isSuccess()) {
            throw new BusinessException(response.code, response.getMsg());
        }
        return response.getData();
    }

    /**
     * 检查响应是否存在数据
     *
     * @param response this
     * @param <T>      泛型
     * @return {@link Boolean}
     */
    public static <T> boolean hasData(Response<T> response) {
        return Objects.nonNull(response) && response.isSuccess() && !ObjectUtils.isEmpty(response.getData());
    }

    /**
     * 只获取有结果的Response，否则直接抛出EMPTY_ERROR异常
     * 如果响应200，但数据为空(集合，数组，Map)，也将抛出EMPTY_ERROR异常
     *
     * @param response this
     * @param <T>      泛型
     */
    public static <T> T getNotEmptyData(Response<T> response) {
        if (Objects.isNull(response)) {
            throw new BusinessException(SystemEnum.INTERNAL_SERVER_ERROR);
        }
        if (!response.isSuccess()) {
            throw new BusinessException(response.code, response.getMsg());
        }
        if (ObjectUtils.isEmpty(response.getData())) {
            throw new BusinessException(SystemEnum.INTERNAL_SERVER_ERROR);
        }
        return response.getData();
    }

    /**
     * 是否响应成功
     *
     * @return {@link Boolean}
     */
    public boolean isSuccess() {
        return Objects.equals(this.code, HttpStatus.HTTP_OK);
    }
}
